package com.dify.knowledge.service;

import com.dify.knowledge.config.DifyProperties;
import com.dify.knowledge.dto.*;
import com.dify.knowledge.exception.DifyApiException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import reactor.core.publisher.Mono;

/**
 * Dify API集成服务
 * 参考文档：https://docs.dify.ai/api-reference
 */
@Slf4j
@Service
public class DifyService {

    private final WebClient appWebClient;
    private final WebClient datasetWebClient;
    private final DifyProperties difyProperties;

    public DifyService(@Qualifier("appWebClient") WebClient appWebClient,
                       @Qualifier("datasetWebClient") WebClient datasetWebClient,
                       DifyProperties difyProperties) {
        this.appWebClient = appWebClient;
        this.datasetWebClient = datasetWebClient;
        this.difyProperties = difyProperties;
    }

    /**
     * 发送问答请求到Dify Chat API
     * 参考：https://docs.dify.ai/api-reference/chat/send-chat-message
     * 
     * @param question 问题内容
     * @param userId 用户ID
     * @return Dify响应
     */
    public DifyChatResponse sendChatMessage(String question, String userId) {
        log.info("调用Dify Chat API，问题：{}，用户ID：{}", question, userId);
        
        try {
            DifyChatRequest request = DifyChatRequest.builder()
                    .query(question)
                    .user(String.valueOf(userId))
                    .responseMode("blocking")
                    .build();

            DifyChatResponse response = appWebClient.post()
                    .uri("/chat-messages")
                    .bodyValue(request)
                    .retrieve()
                    .bodyToMono(DifyChatResponse.class)
                    .block();

            if (response == null) {
                throw new DifyApiException("Dify API返回空响应");
            }

            log.info("Dify Chat API调用成功，消息ID：{}", response.getMessageId());
            return response;

        } catch (WebClientResponseException e) {
            log.error("Dify Chat API调用失败，状态码：{}，响应：{}", e.getStatusCode(), e.getResponseBodyAsString(), e);
            throw new DifyApiException("Dify Chat API调用失败：" + e.getMessage(), e);
        } catch (Exception e) {
            log.error("Dify Chat API调用异常", e);
            throw new DifyApiException("Dify Chat API调用异常：" + e.getMessage(), e);
        }
    }

    /**
     * 上传文档到Dify知识库
     * 
     * @param content 文档文本内容
     * @param fileName 文件名
     * @return Dify文档ID
     */
    public String uploadDocument(String content, String fileName) {
        log.info("上传文档到Dify知识库，文件名：{}", fileName);
        
        try {
            // 构建请求，使用简化的process_rule
            DifyDocumentRequest request = DifyDocumentRequest.builder()
                    .name(fileName)
                    .text(content)
                    .indexingTechnique("high_quality")
                    .processRule(DifyDocumentRequest.ProcessRule.builder()
                            .mode("automatic")
                            .build())
                    .build();

            String datasetId = difyProperties.getDatasetId();
            if (datasetId == null || datasetId.trim().isEmpty()) {
                throw new DifyApiException("Dify Dataset ID未配置，请在application.yml中配置dify.api.dataset-id");
            }
            
            String uri = "/datasets/" + datasetId + "/document/create-by-text";
            log.info("请求URI: {}", uri);
            log.info("完整URL: {}{}", difyProperties.getBaseUrl(), uri);
            log.info("请求体: name={}, text长度={}, indexingTechnique={}, processRule.mode={}", 
                    request.getName(), 
                    request.getText() != null ? request.getText().length() : 0,
                    request.getIndexingTechnique(),
                    request.getProcessRule() != null ? request.getProcessRule().getMode() : null);
            
            // 先获取原始响应字符串，用于调试
            String responseBody = datasetWebClient.post()
                    .uri(uri)
                    .bodyValue(request)
                    .retrieve()
                    .bodyToMono(String.class)
                    .block();
            
            log.info("Dify API原始响应: {}", responseBody);
            
            // 如果响应不为空，说明上传成功
            if (responseBody != null && !responseBody.trim().isEmpty()) {
                log.info("文档上传成功，响应: {}", responseBody);
                
                // 尝试从响应中提取document ID
                // 响应格式可能是: {"document": {"id": "xxx", ...}, "batch": "xxx"}
                try {
                    com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper();
                    com.fasterxml.jackson.databind.JsonNode rootNode = mapper.readTree(responseBody);
                    
                    String documentId = null;
                    
                    // 尝试从document.id获取
                    if (rootNode.has("document") && rootNode.get("document").has("id")) {
                        documentId = rootNode.get("document").get("id").asText();
                    }
                    // 尝试从document_id获取
                    else if (rootNode.has("document_id")) {
                        documentId = rootNode.get("document_id").asText();
                    }
                    // 尝试从id获取
                    else if (rootNode.has("id")) {
                        documentId = rootNode.get("id").asText();
                    }
                    
                    if (documentId != null && !documentId.isEmpty()) {
                        log.info("文档上传成功，Document ID: {}", documentId);
                        return documentId;
                    } else {
                        log.warn("无法从响应中提取Document ID，但上传可能已成功");
                        // 返回batch ID或时间戳作为标识
                        if (rootNode.has("batch")) {
                            return rootNode.get("batch").asText();
                        }
                        return "uploaded_" + System.currentTimeMillis();
                    }
                } catch (Exception parseException) {
                    log.warn("解析响应失败，但上传可能已成功: {}", parseException.getMessage());
                    return "uploaded_" + System.currentTimeMillis();
                }
            }
            
            throw new DifyApiException("Dify文档上传失败，返回空响应");

        } catch (WebClientResponseException e) {
            log.error("Dify文档上传失败，状态码：{}，响应：{}", e.getStatusCode(), e.getResponseBodyAsString(), e);
            throw new DifyApiException("Dify文档上传失败：" + e.getMessage(), e);
        } catch (Exception e) {
            log.error("Dify文档上传异常", e);
            throw new DifyApiException("Dify文档上传异常：" + e.getMessage(), e);
        }
    }

    /**
     * 从Dify知识库删除文档
     * 
     * @param difyDocumentId Dify文档ID
     */
    public void deleteDocument(String difyDocumentId) {
        log.info("从Dify知识库删除文档，文档ID：{}", difyDocumentId);
        
        try {
            String datasetId = difyProperties.getDatasetId();
            if (datasetId == null || datasetId.trim().isEmpty()) {
                throw new DifyApiException("Dify Dataset ID未配置，请在application.yml中配置dify.api.dataset-id");
            }
            
            datasetWebClient.delete()
                    .uri("/datasets/{dataset_id}/documents/{document_id}", datasetId, difyDocumentId)
                    .retrieve()
                    .bodyToMono(Void.class)
                    .block();

            log.info("文档删除成功，Dify文档ID：{}", difyDocumentId);

        } catch (WebClientResponseException e) {
            log.error("Dify文档删除失败，状态码：{}，响应：{}", e.getStatusCode(), e.getResponseBodyAsString(), e);
            throw new DifyApiException("Dify文档删除失败：" + e.getMessage(), e);
        } catch (Exception e) {
            log.error("Dify文档删除异常", e);
            throw new DifyApiException("Dify文档删除异常：" + e.getMessage(), e);
        }
    }

    /**
     * 生成SOP内容
     * 
     * @param topic SOP主题
     * @return SOP内容
     */
    public String generateSop(String topic) {
        log.info("生成SOP内容，主题：{}", topic);
        
        try {
            String prompt = "请基于知识库内容，为以下主题生成详细的标准操作流程（SOP）：" + topic + 
                          "\n\n要求：\n1. 包含明确的步骤说明\n2. 列出注意事项\n3. 只能取知识库中相关流程生成，不能联网搜索或胡编乱造\n4. 如果知识库中没有相关内容，请明确说明，但是如果找到了相关知识库，则不需要说明";

            DifyChatRequest request = DifyChatRequest.builder()
                    .query(prompt)
                    .user("system")
                    .responseMode("blocking")
                    .build();

            DifyChatResponse response = appWebClient.post()
                    .uri("/chat-messages")
                    .bodyValue(request)
                    .retrieve()
                    .bodyToMono(DifyChatResponse.class)
                    .block();

            if (response == null || response.getAnswer() == null) {
                throw new DifyApiException("SOP生成失败，返回空响应");
            }

            log.info("SOP生成成功");
            return response.getAnswer();

        } catch (WebClientResponseException e) {
            log.error("SOP生成失败，状态码：{}，响应：{}", e.getStatusCode(), e.getResponseBodyAsString(), e);
            throw new DifyApiException("SOP生成失败：" + e.getMessage(), e);
        } catch (Exception e) {
            log.error("SOP生成异常", e);
            throw new DifyApiException("SOP生成异常：" + e.getMessage(), e);
        }
    }

    /**
     * 检查响应是否包含知识
     * 
     * @param response Dify响应
     * @return 是否有相关知识
     */
    public boolean hasKnowledge(DifyChatResponse response) {
        if (response.getMetadata() == null || 
            response.getMetadata().getRetrieverResources() == null ||
            response.getMetadata().getRetrieverResources().isEmpty()) {
            return false;
        }
        
        // 检查是否有高相关度的检索结果（分数 > 0.5）
        return response.getMetadata().getRetrieverResources().stream()
                .anyMatch(resource -> resource.getScore() != null && resource.getScore() > 0.5);
    }
}
